#include "StdAfx.h"
#include "Mesh.h"
#include <iostream>
#include <fstream>

using namespace vmml;
using namespace std;



Mesh::Mesh(void)
{
}

Mesh::Mesh(int verts,int trian,int normals,int faces)
{	
	numVerts = verts;
	numNormals = normals;
	numFaces = faces;
	numTriangles = trian;

	//initialize arrays
	pt = new vec3d[numVerts];
	tf = new vec3d[numVerts];
	ptdata = new double[numVerts];
	norm = new vec3d[numNormals];
	//face = new Face[numFaces];
	face = new vmml::vector<1,Face>[numFaces];
	tri = new vmml::vector<3,int>[numTriangles];

	//Assigning numTriangles to face 0
	//this->setFaceCount(0,numTriangles);
	//for(int i = 0;i < numTriangles;i++){
	//	tri[i] = new vmml::vector<3,int>
	//}

	//std::cout << " TESTING ARRAYS " << std::endl;
	//for(int i = 0;i< numFaces;i++){
	//	std::cout << " pt spot  " << i << std::endl;
	//}
	
	//initialize counters
	vertAppend = 0;
	normAppend = 0;
	triAppend = 0;
	//faceAppend = 0;
	//std::cout << "MESH CREATED: " << "verts: " << numVerts << " trianlges: " << numTriangles << " faces: " << numFaces << std::endl;
}

Mesh::~Mesh(void)
{
	//delete pt;
	//delete ptdata;
	//delete norm;
	//delete face;
	//delete tri;
}

void Mesh::setFaceCount(int f, int count){
	//std::cout << "setting facecount" << std::endl;
	this->face[f].x() = Face(count);
	//std::cout << " face " << f << " size " <<  count << std::endl;
}

void Mesh::drawTriangles(double alpha){
	double xcol,ycol,zcol;
	//std::cout << "starting draw!" << std::endl;
	/*for(int i = 0;i<vertAppend;i++){
		std::cout << "intensity: " << tf[i] << std::endl;
	}*/

	for(int f = 0; f < numFaces;f++){
		//std::cout << "face " << f << std::endl;
		//std::cout << "for " << face[f].nVerts << " vertices " << std::endl;
		for(int t = 0;t< face[f].x().nTri;t++){
			int ti = face[f].x().tri[t].triIndex; //FIND INDEX ti OF TRIANGLE IN FACE

			int vi1 = tri[ti].x(); //FIND INDEX OF VERTEX1 OF TRIANGLE WITH INDEX ti
			int vi2 = tri[ti].y(); //FIND INDEX OF VERTEX2 OF TRIANGLE WITH INDEX ti
			int vi3 = tri[ti].z(); //FIND INDEX OF VERTEX3 OF TRIANGLE WITH INDEX ti

			vmml::vec3d normal;
			normal = norm[ti];
			
			//If the triangle does not contain an empty datapoint
			//if(!(pt[vi1].z() == 0) || !(pt[vi2].z() == 0) || !(pt[vi3].z() == 0)){
				//DRAW TRIANGLE
				glBegin(GL_TRIANGLES);
					glNormal3f(normal.x(),normal.y(),normal.z());
					
					glColor3d(tf[vi1].x(),tf[vi1].y(),tf[vi1].z());
					glVertex3f(pt[vi1].x(),pt[vi1].y(),pt[vi1].z());

					glColor3d(tf[vi2].x(),tf[vi2].y(),tf[vi2].z());
					glVertex3f(pt[vi2].x(),pt[vi2].y(),pt[vi2].z());

					glColor3d(tf[vi3].x(),tf[vi3].y(),tf[vi3].z());
					glVertex3f(pt[vi3].x(),pt[vi3].y(),pt[vi3].z());
				glEnd();
			//}
		}
	}
}

//Create an .obj wavefront object file from the triangle mesh
void Mesh::toWaveFrontObject(){
	cout << "Creating .OBJ File -> files/mesh.obj" << endl;
	ofstream tempVertFile,tempNormFile,tempFaceFile,objMesh;
	tempVertFile.open("files/vert.temp",ios::trunc);
	tempNormFile.open("files/norm.temp",ios::trunc);
	tempFaceFile.open("files/face.temp",ios::trunc);
	remove("files/mesh.obj");
	objMesh.open("files/mesh.obj",ios::app);

	//Add verteces
	tempVertFile << "#List of Vertices, with (x,y,z[,w]) coordinates, w is optional." << "\n";
	/*for(int i = 0;i<this->vertAppend;i++){
		objfile << "v"  << i << " " << pt[i].x() << " " << pt[i].y() << " " << pt[i].z() << "\n";
	}*/
	//Add normals
	tempNormFile << "#Normals in (x,y,z) form." << "\n";
	/*for(int i = 0;i<this->triAppend;i++){
		objfile << "vn"  << i << " " << norm[i].x() << " " << norm[i].y() << " " << norm[i].z() << "\n";
	}*/
	//////Define Face
	tempFaceFile << "#Vertex/normal." << "\n";
	//for(int i = 0;i<this->triAppend;i++){
	//	objfile << "f " << "v" << i << "//vn" << i <<  " ";
	//}
	int vcount = 1;
	int ncount = 1;
	for(int f = 0; f < numFaces;f++){
		//std::cout << "face " << f << std::endl;
		//std::cout << "for " << face[f].nVerts << " vertices " << std::endl;
		for(int t = 0;t< face[f].x().nTri;t++){
			int ti = face[f].x().tri[t].triIndex; //FIND INDEX ti OF TRIANGLE IN FACE

			int vi1 = tri[ti].x(); //FIND INDEX OF VERTEX1 OF TRIANGLE WITH INDEX ti
			int vi2 = tri[ti].y(); //FIND INDEX OF VERTEX2 OF TRIANGLE WITH INDEX ti
			int vi3 = tri[ti].z(); //FIND INDEX OF VERTEX3 OF TRIANGLE WITH INDEX ti

			vmml::vec3d normal;
			normal = norm[ti];
			
			//Define the 3 vertices on the face as using the same normal
			tempFaceFile << "f " << vcount << "//" << ncount  << " " << vcount+1 << "//" << ncount << " " << vcount+2 << "//" << ncount << "\n";
			
			//Add the 3 vertices
			//tempVertFile << "v"  << vcount << " " << pt[vi1].x() << " " << pt[vi1].y() << " " << pt[vi1].z() << "\n";
			tempVertFile << "v" << " " << pt[vi1].x() << " " << pt[vi1].y() << " " << pt[vi1].z() << "\n";
			vcount++;
			//tempVertFile << "v"  << vcount << " " << pt[vi2].x() << " " << pt[vi2].y() << " " << pt[vi2].z() << "\n";
			tempVertFile << "v" << " " << pt[vi2].x() << " " << pt[vi2].y() << " " << pt[vi2].z() << "\n";
			vcount++;
			//tempVertFile << "v"  << vcount << " " << pt[vi3].x() << " " << pt[vi3].y() << " " << pt[vi3].z() << "\n";
			tempVertFile << "v" << " " << pt[vi3].x() << " " << pt[vi3].y() << " " << pt[vi3].z() << "\n";
			vcount++;
			
			//Add the shared normal
			//tempNormFile << "vn"  << ncount << " " << normal.x() << " " << normal.y() << " " << normal.z() << "\n";
			tempNormFile << "vn" << " " << normal.x() << " " << normal.y() << " " << normal.z() << "\n";
			ncount++;

		}
	}
	tempVertFile.close();
	tempNormFile.close();
	tempFaceFile.close();
	//Append the 3 files
	string line;
	ifstream tempFile_vert("files/vert.temp");
	if (tempFile_vert.is_open()){
		while ( tempFile_vert.good() ){
			getline (tempFile_vert,line);
			objMesh << line << "\n";
		}
	}
	tempFile_vert.close();

	ifstream tempFile_norm("files/norm.temp");
	if (tempFile_norm.is_open()){
		while ( tempFile_norm.good() ){
			getline (tempFile_norm,line);
			objMesh << line << "\n";
		}
	}
	tempFile_norm.close();

	ifstream tempFile_face("files/face.temp");
	if (tempFile_face.is_open()){
		while ( tempFile_face.good() ){
			getline (tempFile_face,line);
			objMesh << line << "\n";
		}
	}
	tempFile_face.close();
	
	remove("files/face.temp");
	remove("files/vert.temp");
	remove("files/norm.temp");
	objMesh.close();
	
}

void Mesh::addPoint(vec3d& v,vec3d& n,int f,double ftle){
	//std::cout << " VERTEX SIZE " << numVerts << std::endl;;
	//std::cout << " NORMAL SIZE " << numNormals << std::endl;;
	//std::cout << " FACE SIZE " << numFaces << std::endl;;
	//std::cout << " ADDING VERTEX TO SPOT " << vertAppend << std::endl;
	//std::cout << " ADDING NORMAL TO SPOT " << normAppend << std::endl;

	pt[vertAppend] = v;
	ptdata[vertAppend] = ftle;
	norm[normAppend] = n;

	face[f].x().vert[vertAppend].vertIndex = vertAppend;
	//std::cout << "VERTINDEX OF POINT: "  << face[f].getVertID()[vertAppend].vertIndex << std::endl;
	face[f].x().vert[normAppend].normIndex = normAppend;

	//std::cout << "NORMINDEX OF POINT: "  << face[f].getVertID()[normAppend].normIndex << std::endl;
	
	vertAppend++;
	//normAppend++;
	//std::cout << "here!" << std::endl;


}

vec3d* Mesh::getVertices(){
	return pt;
}

int Mesh::getNumberOfVertices(){
	return vertAppend;
}


int Mesh::findVertex(vec3d &v){
	int indx = -1;
	for(int i = 0;i<numVerts;i++){
		if(v == pt[i]){
			indx = i;
			break;
		}
	}

	return indx;
}


void Mesh::addTriangle(vec3d& v1, vec3d& v2, vec3d& v3,int f,vec3d& i1,vec3d& i2,vec3d& i3){
	//std::cout << "ADDING TRIANGLE" << std::endl;
	/*std::cout << std::endl;
	std::cout << "==== NEW TRIANGLE STARTED ====" << std::endl;
	std::cout << "vertex array size " << this->numVerts << std::endl;
	std::cout << "tri size: " << face[f].nTri << std::endl;
	std::cout << "traingles in mesh: " << numTriangles << std::endl;*/
	//Calculat surface normal
	int found;
	vmml::vec3d normal,u,v;
	u = v2 - v1;
	v = v3 - v1;

	normal.x() = (u.y() * v.z()) - (u.z() * v.y());
	normal.y() = (u.z() * v.x()) - (u.x() * v.z());
	normal.z() = (u.x() * v.y()) - (u.y() * v.x());

	norm[triAppend] = normal;

	vmml::vector<3,int> triangle;

	found = findVertex(v1);
	if(found >= 0){
		triangle.x() = found;
	}
	else{
		pt[vertAppend] = v1;
		tf[vertAppend] = i1;
		triangle.x() = vertAppend;
		vertAppend++;
	}

	found = findVertex(v2);
	if(found >= 0){
		triangle.y() = found;
	}
	else{
		pt[vertAppend] = v2;
		tf[vertAppend] = i2;
		triangle.y() = vertAppend;
		vertAppend++;
	}

	found = findVertex(v3);
	if(found >= 0){
		triangle.z() = found;
	}
	else{
		pt[vertAppend] = v3;
		tf[vertAppend] = i3;
		triangle.z() = vertAppend;
		vertAppend++;
	}
	//std::cout << "test" << std::endl;
	/*std::cout << "ADDED VERTEX: " << vertAppend << std::endl;
	std::cout << "ADDING TRIANGLE: " << (triAppend+1) << std::endl;*/
	tri[triAppend] = triangle;
	face[f].x().tri[triAppend].triIndex = triAppend; 
	/*std::cout << "TRIINDEX: " << face[f].x().tri[triAppend].triIndex << std::endl;
	std::cout << "TRIAPPEND: " << triAppend << std::endl;*/
	triAppend++;
}

void Mesh::addEigenTriangle(Eigen::VectorXd& v1, Eigen::VectorXd& v2, Eigen::VectorXd& v3,int f, Eigen::VectorXd& intensity){
	//std::cout << "ADDING TRIANGLE" << std::endl;
	/*std::cout << std::endl;
	std::cout << "==== NEW TRIANGLE STARTED ====" << std::endl;
	std::cout << "vertex array size " << this->numVerts << std::endl;
	std::cout << "tri size: " << face[f].nTri << std::endl;
	std::cout << "traingles in mesh: " << numTriangles << std::endl;*/
	//Calculat surface normal
	int found;
	vmml::vec3d normal,u,v,v_1,v_2,v_3;
	vmml::vec3d i;
	v_1.x() = v1.x();
	v_1.y() = v1.y();
	v_1.z() = v1.z();

	v_2.x() = v2.x();
	v_2.y() = v2.y();
	v_2.z() = v2.z();
	
	v_3.x() = v3.x();
	v_3.y() = v3.y();
	v_3.z() = v3.z();

	i.x() = intensity.x();
	i.y() = intensity.y();
	i.z() = intensity.z();

	u = v_2 - v_1;
	v = v_3 - v_1;

	normal.x() = (u.y() * v.z()) - (u.z() * v.y());
	normal.y() = (u.z() * v.x()) - (u.x() * v.z());
	normal.z() = (u.x() * v.y()) - (u.y() * v.x());

	norm[triAppend] = normal;

	vmml::vector<3,int> triangle;

	found = findVertex(v_1);
	if(found >= 0){
		triangle.x() = found;
	}
	else{
		pt[vertAppend] = v_1;
		tf[vertAppend] = i;
		triangle.x() = vertAppend;
		vertAppend++;
	}

	found = findVertex(v_2);
	if(found >= 0){
		triangle.y() = found;
	}
	else{
		pt[vertAppend] = v_2;
		tf[vertAppend] = i;
		triangle.y() = vertAppend;
		vertAppend++;
	}

	found = findVertex(v_3);
	if(found >= 0){
		triangle.z() = found;
	}
	else{
		pt[vertAppend] = v_3;
		tf[vertAppend] = i;
		triangle.z() = vertAppend;
		vertAppend++;
	}
	//std::cout << "test" << std::endl;
	/*std::cout << "ADDED VERTEX: " << vertAppend << std::endl;
	std::cout << "ADDING TRIANGLE: " << (triAppend+1) << std::endl;*/
	tri[triAppend] = triangle;
	face[f].x().tri[triAppend].triIndex = triAppend; 
	/*std::cout << "TRIINDEX: " << face[f].x().tri[triAppend].triIndex << std::endl;
	std::cout << "TRIAPPEND: " << triAppend << std::endl;*/
	triAppend++;
}
